-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local lu = require 'luaunit'
local c_optical_module = require 'device.class.optical_module'
local fructl = require 'infrastructure.fructl'
local skynet = require 'skynet'
local npu_imu_cmd = require 'npu.hdk_cmd'
local npu_om_event_debounce_config = require 'event.debounce_config.npu_om'
local log = require 'mc.logging'

TEST_optical_module = {}

function TEST_optical_module:test_reset_npu_om()
    c_optical_module:reset_npu_om()
    lu.assertEquals(c_optical_module.MediaInterfaceFaultStatus, 0xFFFF)
end

function TEST_optical_module:test_get_optical_temp_scheduler()    
    c_optical_module.ncsi_config_obj = {
        channel_id = 1,
        package_id = 1,
        test1 = {respons_first = "test_func", value = function ()
            return "test_func"
        end},
        test2 = {respons_second = "test2", value = function ()
            return nil
        end},
        test_func = function(obj, t)
            return t
        end,
    }
    function c_optical_module.ncsi_config_obj:OpticalGetIdentifier(t1)
        if t1.channel_id == self.channel_id then
            return self.test1
        end
        return self.test2
    end
    function c_optical_module.ncsi_config_obj:OpticalTemp(t1)
        return t1
    end
    c_optical_module.PortID = 2
    c_optical_module.package_id = 2
    local ret = c_optical_module:get_optical_temp_scheduler()
    lu.assertEquals(ret.channel_id, 2)
    lu.assertEquals(ret.package_id, 2)
    c_optical_module.PortID = 1
    c_optical_module.package_id = 1
    local ret = c_optical_module:get_optical_temp_scheduler()
    lu.assertEquals(ret.channel_id, 1)
    lu.assertEquals(ret.package_id, 1)
end

function TEST_optical_module:test_get_info_from_imu_task()
    fructl.get_power_status = function()
        return "OFF"
    end
    c_optical_module:check_info_from_imu(1, {PowerOn = 0})
    lu.assertEquals(c_optical_module.MediaInterfaceFaultStatus, 0xFFFF)

    fructl.get_power_status = function()
        return "ON"
    end
    c_optical_module.is_npu_heartbeat_loss = true
    c_optical_module:check_info_from_imu(1, {PowerOn = 1})

    c_optical_module.is_npu_heartbeat_loss = false
    c_optical_module.init_npu_optical_module_info = function()
        c_optical_module.MediaInterfaceFaultStatus = 0x00
        return false, "test error"
    end
    npu_imu_cmd.get_optical_info_from_imu = function()
        return false;
    end
    c_optical_module:check_info_from_imu(1, {PowerOn = 1})
    lu.assertEquals(c_optical_module.MediaInterfaceFaultStatus, 0x00)
    c_optical_module.init_npu_optical_module_info = function(id)
        c_optical_module.MediaInterfaceFaultStatus = 0x01
        return id[1]
    end
    c_optical_module:check_info_from_imu(1, {PowerOn = 1})
    lu.assertEquals(c_optical_module.MediaInterfaceFaultStatus, 0x01)

    local c_get_parent = c_optical_module.get_parent
    local c_init = c_optical_module.init
    local c_check_info_from_imu = c_optical_module.check_info_from_imu
    c_optical_module.get_parent = function()
        return {}
    end
    c_optical_module.init = function()
        return {}
    end
    local count = 0
    c_optical_module.check_info_from_imu = function()
        count = count + 1
        if count > 1 then
            error("count 1")
        end
    end
    pcall(c_optical_module.get_info_from_imu_task, c_optical_module)
    c_optical_module.get_parent = c_get_parent
    c_optical_module.init = c_init
    c_optical_module.check_info_from_imu = c_check_info_from_imu
end

function TEST_optical_module:test_update_prbs_test_info()
    c_optical_module.init_npu_optical_module_info = function(id)
        c_optical_module.SerialNumber = '035JUALDQ5003303'
        c_optical_module.Presence = 1
        c_optical_module.PRBSTestSupported = nil
        return id[1]
    end
    c_optical_module:check_info_from_imu(1, {PowerOn = 1})
    pcall(c_optical_module.update_prbs_test_info, c_optical_module, 1)
    lu.assertEquals(c_optical_module.PRBSTestSupported, false)

    c_optical_module.SerialNumber = '035JUALDQ5003304'
    pcall(c_optical_module.update_prbs_test_info, c_optical_module, 1)
    lu.assertEquals(c_optical_module.PRBSTestSupported, false)

    c_optical_module.SerialNumber = ''
    pcall(c_optical_module.update_prbs_test_info, c_optical_module, 1)
    lu.assertEquals(c_optical_module.PRBSTestSupported, false)

    c_optical_module.Presence = 0
    pcall(c_optical_module.update_prbs_test_info, c_optical_module, 1)
    lu.assertEquals(c_optical_module.PRBSTestSupported, false)
end

function TEST_optical_module:test_npu_om_event_conf()
    local npu_om = npu_om_event_debounce_config 
    lu.assertNotEquals(npu_om, nil)
    local om_obj = {
        get_parent = function()
            return {
                get_parent = function()
                    return {
                        Name = 1,
                    }
                end,
                NpuID = 1
            }
        end
    }
    local event_test = {}
    local function test_event(event)       
            event_test.EventKeyId = event.EventKeyId
            event_test.SubjectType = event.SubjectType
            if event.EventCode == "0x29000017" or event.EventCode == "0x29000011" then
                    om_obj[event.prop_names[1]] = {1, 2, 3, 5, 6, 7, 8, 9, 10}
                    om_obj[event.prop_names[2]] = 3
                    om_obj[event.prop_names[3]] = 0
            else
                for k, prop in ipairs(event.prop_names) do                
                    om_obj[prop] = k
                end
            end
            event_test.type = event.type
            event_test.cont_num = event.cont_num
            event_test.trigger_fun = event.trigger_fun
            event_test.get_args = event.get_args
            event_test.trigger_fun = event.trigger_fun
            lu.assertNotEquals(event_test.trigger_fun(om_obj), nil)
            lu.assertNotEquals(event.get_args(om_obj), nil)
    end
    for _, events in pairs(npu_om) do
        for _, event in pairs(events) do
            test_event(event)
        end
    end
end

function TEST_optical_module:test_mctp()
    c_optical_module.schedulers = {}
    c_optical_module.connect_signal = function () end
    local mctp_obj = {
        OpticalModuleInfo = function()
            return {
                on_data_change = {
                    on = function(data) end
                },
                start = function () end
            }
        end,
        OpticalTemp = function()
            return {
                on_data_change = {
                    on = function(data) end
                },
                start = function () end
            }
        end,
        OpticalIdentifier = function()
            return {
                value = function () end
            }
        end
    }
    c_optical_module:update_ncsi_properties(mctp_obj, 1)
    c_optical_module:update_optical_temp_by_ncsi()
    c_optical_module:update_NSCI_optical_module_info()
    c_optical_module:restart_update_NSCI_optical_module_info(mctp_obj, 1)
end

function TEST_optical_module:test_update_asset_data_info()
    c_optical_module:update_asset_data_info()
    lu.assertEquals(c_optical_module.Model, 'N/A')
end

function TEST_optical_module:test_get_optical_info_from_imu_retry()
    local origin_get_optical_info_from_imu = npu_imu_cmd.get_optical_info_from_imu

    npu_imu_cmd.get_optical_info_from_imu = function()
        return true, true
    end
    local ok, result = c_optical_module:get_optical_info_from_imu_retry()
    lu.assertIsTrue(ok and result)

    npu_imu_cmd.get_optical_info_from_imu = function()
        return false, true
    end
    ok, result = c_optical_module:get_optical_info_from_imu_retry()
    lu.assertIsFalse(ok and result)

    npu_imu_cmd.get_optical_info_from_imu = origin_get_optical_info_from_imu
end

function TEST_optical_module:test_init_npu_optical_module_info()
    local origin_get_optical_info_from_imu_retry = c_optical_module.get_optical_info_from_imu_retry
    c_optical_module.get_optical_info_from_imu_retry = function(id)
        return true, true
    end
    local id
    c_optical_module:init_npu_optical_module_info(id)
    lu.assertIsTrue(c_optical_module.npu_optical_module_info_abnormal)

    c_optical_module.get_optical_info_from_imu_retry = function(id)
        return true, false
    end
    c_optical_module:init_npu_optical_module_info(id)
    lu.assertIsTrue(c_optical_module.npu_optical_module_info_abnormal)

    c_optical_module.get_optical_info_from_imu_retry = origin_get_optical_info_from_imu_retry
end

function TEST_optical_module:test_check_info_from_imu()
    c_optical_module.is_first_get_info_from_imu = false
    local origin_get_power_status = fructl.get_power_status
    fructl.get_power_status = function()
        return 'OFF'
    end
    local id
    c_optical_module:check_info_from_imu(id, {})
    lu.assertIsFalse(c_optical_module.npu_optical_module_info_abnormal)

    c_optical_module.is_npu_heartbeat_loss = true
    c_optical_module:check_info_from_imu(id, {})
    lu.assertIsFalse(c_optical_module.npu_optical_module_info_abnormal)

    fructl.get_power_status = origin_get_power_status
end

-- 保存原始函数引用，用于测试后还原
local original_log_debug = log.debug

-- 测试用例：测试 get_diagnostic_by_ibma_success 为 true 时的情况
function TEST_optical_module:test_reset_with_ibma_success_true()
    -- Mock log.debug 函数
    local debug_called = false
    log.debug = function(msg)
        debug_called = true
    end
    -- 保存原始值
    local original_get_diagnostic_by_ibma_success = c_optical_module.get_diagnostic_by_ibma_success
    -- 设置 get_diagnostic_by_ibma_success 为 true
    c_optical_module.get_diagnostic_by_ibma_success = true
    -- Mock set_prop 方法来检测是否被调用
    local set_prop_called = false
    local original_set_prop = c_optical_module.set_prop
    c_optical_module.set_prop = function(...)
        set_prop_called = true
    end
    -- 调用 reset 方法
    c_optical_module:reset()
    -- 断言：当 get_diagnostic_by_ibma_success 为 true 时
    -- 1. 函数应该直接返回，不执行后续代码
    -- 2. set_prop 不应该被调用
    -- 3. debug 日志不应该被记录
    lu.assertFalse(set_prop_called, "set_prop should not be called when get_diagnostic_by_ibma_success is true")
    lu.assertFalse(debug_called, "debug log should not be called when get_diagnostic_by_ibma_success is true")
    -- 还原函数
    c_optical_module.set_prop = original_set_prop
    c_optical_module.get_diagnostic_by_ibma_success = original_get_diagnostic_by_ibma_success
    log.debug = original_log_debug
end

-- 测试用例：测试 c_optical_channel.collection.objects 为 nil 时的情况
function TEST_optical_module:test_reset_diagnostic_info_with_nil_collection()
    local c_optical_channel = require 'device.class.optical_channel'
    -- 保存原始值
    local original_collection_objects = c_optical_channel.collection.objects
    -- Mock c_optical_channel.collection.objects 为 nil
    c_optical_channel.collection.objects = nil
    -- Mock ipairs 函数来检测是否被调用
    local ipairs_called = false
    local original_ipairs = ipairs
    ipairs = function(t)
        ipairs_called = true
        return original_ipairs(t)
    end
    -- 调用 reset_diagnostic_info 方法
    c_optical_module:reset_diagnostic_info()
    -- 断言：当 c_optical_channel.collection.objects 为 nil 时
    -- 1. 函数应该在条件判断处直接返回
    -- 2. ipairs 不应该被调用（因为后续的循环不会执行）
    lu.assertFalse(ipairs_called, "ipairs should not be called when c_optical_channel.collection.objects is nil")
    -- 还原函数和值
    c_optical_channel.collection.objects = original_collection_objects
    ipairs = original_ipairs
end

-- 测试用例：测试 c_optical_channel.collection.objects 不为 nil 时的循环逻辑
function TEST_optical_module:test_reset_diagnostic_info_with_valid_collection()
    local c_optical_channel = require 'device.class.optical_channel'
    -- 保存原始值
    local original_collection_objects = c_optical_channel.collection.objects
    local original_name = c_optical_module.name
    -- 设置 self.name 用于匹配
    c_optical_module.name = "test_optical_module"
    -- Mock channel对象
    local reset_diagnostic_info_called = false
    local get_parent_called = false
    local mock_channel = {
        get_parent = function()
            get_parent_called = true
            return {
                name = "test_optical_module"  -- 与self.name匹配
            }
        end,
        reset_diagnostic_info = function()
            reset_diagnostic_info_called = true
        end
    }
    -- Mock c_optical_channel.collection.objects 为包含mock_channel的数组
    c_optical_channel.collection.objects = {mock_channel}
    -- 调用 reset_diagnostic_info 方法
    c_optical_module:reset_diagnostic_info()
    -- 断言：当 c_optical_channel.collection.objects 不为 nil 且匹配条件时
    -- 1. channel:get_parent() 应该被调用
    -- 2. channel:reset_diagnostic_info() 应该被调用
    lu.assertTrue(get_parent_called, "channel:get_parent() should be called")
    lu.assertTrue(reset_diagnostic_info_called, "channel:reset_diagnostic_info() should be called")
    -- 还原原始值
    c_optical_channel.collection.objects = original_collection_objects
    c_optical_module.name = original_name
end

-- 测试 update_optical_temp_by_ncsi 函数
function TEST_optical_module:test_update_optical_temp_by_ncsi()
    local log = require('mc.logging')
    local original_error = log.error
    local original_NetworkAdapterId = c_optical_module.NetworkAdapterId
    local original_PortID = c_optical_module.PortID
    local original_ncsi_schedulers = c_optical_module.ncsi_schedulers
    local original_get_properties_res = c_optical_module.get_properties_res
    local original_get_optical_temp_scheduler = c_optical_module.get_optical_temp_scheduler
    local original_connect_signal = c_optical_module.connect_signal
    local error_called = false
    local mock_scheduler = {}
    
    log.error = function(self, fmt, ...)
        error_called = true
    end
    
    c_optical_module.NetworkAdapterId = "TestAdapter"
    c_optical_module.PortID = 1
    c_optical_module.ncsi_schedulers = {}
    c_optical_module.get_properties_res = {}
    c_optical_module.get_optical_temp_scheduler = function() return mock_scheduler end
    c_optical_module.connect_signal = function(self, signal, callback) 
        if signal == mock_scheduler.on_data_change then
            mock_scheduler.data_cb = callback
        elseif signal == mock_scheduler.on_error then
            mock_scheduler.error_cb = callback
        end
    end
    
    mock_scheduler.on_data_change = {}
    mock_scheduler.on_error = {}
    mock_scheduler.start = function() end
    
    c_optical_module:update_optical_temp_by_ncsi()
    
    -- 测试数据变化
    mock_scheduler.data_cb(55)
    lu.assertTrue(c_optical_module.get_properties_res.TempFromNcsi)
    
    -- 测试错误回调
    c_optical_module.get_properties_res.TempFromNcsi = true
    mock_scheduler.error_cb()
    lu.assertFalse(c_optical_module.get_properties_res.TempFromNcsi)
    lu.assertTrue(error_called)
    
    log.error = original_error
    c_optical_module.NetworkAdapterId = original_NetworkAdapterId
    c_optical_module.PortID = original_PortID
    c_optical_module.ncsi_schedulers = original_ncsi_schedulers
    c_optical_module.get_properties_res = original_get_properties_res
    c_optical_module.get_optical_temp_scheduler = original_get_optical_temp_scheduler
    c_optical_module.connect_signal = original_connect_signal
end

-- 测试 update_optical_voltage_by_ncsi 函数
function TEST_optical_module:test_update_optical_voltage_by_ncsi()
    local log = require('mc.logging')
    local original_debug = log.debug
    local original_error = log.error
    local original_notice = log.notice
    local original_NetworkAdapterId = c_optical_module.NetworkAdapterId
    local original_PortID = c_optical_module.PortID
    local original_ncsi_schedulers = c_optical_module.ncsi_schedulers
    local original_ncsi_config_obj = c_optical_module.ncsi_config_obj
    local original_get_properties_res = c_optical_module.get_properties_res
    local original_package_id = c_optical_module.package_id
    local original_connect_signal = c_optical_module.connect_signal
    local log_calls = {}
    local mock_scheduler = {}
    
    log.debug = function(self, fmt, ...) 
        table.insert(log_calls, {type='debug', fmt=fmt, args={...}}) 
    end
    log.error = function(self, fmt, ...) 
        table.insert(log_calls, {type='error', fmt=fmt, args={...}}) 
    end
    log.notice = function(self, fmt, ...) 
        table.insert(log_calls, {type='notice', fmt=fmt, args={...}}) 
    end
    
    c_optical_module.NetworkAdapterId = "TestAdapter"
    c_optical_module.PortID = 1
    c_optical_module.ncsi_schedulers = {}
    c_optical_module.get_properties_res = {}
    c_optical_module.package_id = 1
    c_optical_module.ncsi_config_obj = { 
        OpticalVoltage1 = function(self, params) return mock_scheduler end 
    }
    c_optical_module.connect_signal = function(self, signal, callback) 
        if signal == mock_scheduler.on_data_change then
            mock_scheduler.data_cb = callback
        elseif signal == mock_scheduler.on_error then
            mock_scheduler.error_cb = callback
        end
    end
    
    mock_scheduler.on_data_change = {}
    mock_scheduler.on_error = {}
    mock_scheduler.start = function() end
    
    c_optical_module:update_optical_voltage_by_ncsi(1)
    
    -- 测试启动日志
    lu.assertEquals(log_calls[1].fmt, 
        '%s optical_module_%s update optical voltage by ncsi start')
    lu.assertEquals(log_calls[1].args[1], "TestAdapter")
    lu.assertEquals(log_calls[1].args[2], 1)
    
    -- 测试数据变化
    mock_scheduler.data_cb(3.3)
    lu.assertTrue(c_optical_module.get_properties_res.VoltageFromNcsi)
    lu.assertEquals(#log_calls, 2)
    lu.assertEquals(log_calls[2].fmt, 
        '%s optical_module_%s update optical voltage to %s by ncsi')
    
    -- 测试错误回调
    c_optical_module.get_properties_res.VoltageFromNcsi = true
    mock_scheduler.error_cb()
    lu.assertFalse(c_optical_module.get_properties_res.VoltageFromNcsi)
    lu.assertEquals(log_calls[3].fmt, 
        '%s optical_module_%s update optical voltage by ncsi on_error')
    
    log.debug = original_debug
    log.error = original_error
    log.notice = original_notice
    c_optical_module.NetworkAdapterId = original_NetworkAdapterId
    c_optical_module.PortID = original_PortID
    c_optical_module.ncsi_schedulers = original_ncsi_schedulers
    c_optical_module.ncsi_config_obj = original_ncsi_config_obj
    c_optical_module.get_properties_res = original_get_properties_res
    c_optical_module.package_id = original_package_id
    c_optical_module.connect_signal = original_connect_signal
end

-- 测试 update_optical_bias_by_ncsi 函数
function TEST_optical_module:test_update_optical_bias_by_ncsi()
    local log = require('mc.logging')
    local original_debug = log.debug
    local original_error = log.error
    local original_notice = log.notice
    local original_NetworkAdapterId = c_optical_module.NetworkAdapterId
    local original_PortID = c_optical_module.PortID
    local original_ncsi_schedulers = c_optical_module.ncsi_schedulers
    local original_ncsi_config_obj = c_optical_module.ncsi_config_obj
    local original_get_properties_res = c_optical_module.get_properties_res
    local original_package_id = c_optical_module.package_id
    local log_calls = {}
    local mock_scheduler = {}
    
    log.debug = function(self, fmt, ...) 
        table.insert(log_calls, {type='debug', fmt=fmt, args={...}}) 
    end
    log.error = function(self, fmt, ...) 
        table.insert(log_calls, {type='error', fmt=fmt, args={...}}) 
    end
    log.notice = function(self, fmt, ...) 
        table.insert(log_calls, {type='notice', fmt=fmt, args={...}}) 
    end
    
    c_optical_module.NetworkAdapterId = "TestAdapter"
    c_optical_module.PortID = 1
    c_optical_module.ncsi_schedulers = {}
    c_optical_module.get_properties_res = {}
    c_optical_module.package_id = 1
    c_optical_module.ncsi_config_obj = { 
        OpticalBias1 = function(self, params) return mock_scheduler end 
    }
    c_optical_module.connect_signal = function(self, signal, callback) 
        if signal == mock_scheduler.on_data_change then
            mock_scheduler.data_cb = callback
        elseif signal == mock_scheduler.on_error then
            mock_scheduler.error_cb = callback
        end
    end
    
    mock_scheduler.on_data_change = {}
    mock_scheduler.on_error = { on = function(self, cb) mock_scheduler.error_cb = cb end }
    mock_scheduler.start = function() end
    
    c_optical_module:update_optical_bias_by_ncsi(1)
    
    -- 测试启动日志
    lu.assertEquals(log_calls[1].fmt, 
        '%s optical_module_%s update optical bias by ncsi start')
    
    -- 测试数据变化
    mock_scheduler.data_cb({10.5, 11.2})
    lu.assertTrue(c_optical_module.get_properties_res.BiasFromNcsi)
    
    -- 测试错误回调
    c_optical_module.get_properties_res.BiasFromNcsi = true
    mock_scheduler.error_cb()
    lu.assertFalse(c_optical_module.get_properties_res.BiasFromNcsi)
    
    log.debug = original_debug
    log.error = original_error
    log.notice = original_notice
    c_optical_module.NetworkAdapterId = original_NetworkAdapterId
    c_optical_module.PortID = original_PortID
    c_optical_module.ncsi_schedulers = original_ncsi_schedulers
    c_optical_module.ncsi_config_obj = original_ncsi_config_obj
    c_optical_module.get_properties_res = original_get_properties_res
    c_optical_module.package_id = original_package_id
end

-- 测试 update_optical_input_power_by_ncsi 函数
function TEST_optical_module:test_update_optical_input_power_by_ncsi()
    local log = require('mc.logging')
    local original_debug = log.debug
    local original_error = log.error
    local original_notice = log.notice
    local original_NetworkAdapterId = c_optical_module.NetworkAdapterId
    local original_PortID = c_optical_module.PortID
    local original_ncsi_schedulers = c_optical_module.ncsi_schedulers
    local original_ncsi_config_obj = c_optical_module.ncsi_config_obj
    local original_get_properties_res = c_optical_module.get_properties_res
    local original_package_id = c_optical_module.package_id
    local log_calls = {}
    local mock_scheduler = {}
    
    log.debug = function(self, fmt, ...) 
        table.insert(log_calls, {type='debug', fmt=fmt, args={...}}) 
    end
    log.error = function(self, fmt, ...) 
        table.insert(log_calls, {type='error', fmt=fmt, args={...}}) 
    end
    log.notice = function(self, fmt, ...) 
        table.insert(log_calls, {type='notice', fmt=fmt, args={...}}) 
    end
    
    c_optical_module.NetworkAdapterId = "TestAdapter"
    c_optical_module.PortID = 1
    c_optical_module.ncsi_schedulers = {}
    c_optical_module.get_properties_res = {}
    c_optical_module.package_id = 1
    c_optical_module.ncsi_config_obj = { 
        OpticalInputPower1 = function(self, params) return mock_scheduler end 
    }
    c_optical_module.connect_signal = function(self, signal, callback) 
        if signal == mock_scheduler.on_data_change then
            mock_scheduler.data_cb = callback
        elseif signal == mock_scheduler.on_error then
            mock_scheduler.error_cb = callback
        end
    end
    
    mock_scheduler.on_data_change = {}
    mock_scheduler.on_error = {}
    mock_scheduler.start = function() end
    
    c_optical_module:update_optical_input_power_by_ncsi(1)
    
    -- 测试启动日志
    lu.assertEquals(log_calls[1].fmt, 
        '%s optical_module_%s update optical input power by ncsi start')
    
    -- 测试数据变化
    mock_scheduler.data_cb({-5.2, -6.1})
    lu.assertTrue(c_optical_module.get_properties_res.RxPowerFromNcsi)
    
    -- 测试错误回调
    c_optical_module.get_properties_res.RxPowerFromNcsi = true
    mock_scheduler.error_cb()
    lu.assertFalse(c_optical_module.get_properties_res.RxPowerFromNcsi)
    
    log.debug = original_debug
    log.error = original_error
    log.notice = original_notice
    c_optical_module.NetworkAdapterId = original_NetworkAdapterId
    c_optical_module.PortID = original_PortID
    c_optical_module.ncsi_schedulers = original_ncsi_schedulers
    c_optical_module.ncsi_config_obj = original_ncsi_config_obj
    c_optical_module.get_properties_res = original_get_properties_res
    c_optical_module.package_id = original_package_id
end

-- 测试 update_optical_module_static_info_by_ncsi 函数
function TEST_optical_module:test_update_optical_module_static_info_by_ncsi()
    local log = require('mc.logging')
    local original_notice = log.notice
    local original_error = log.error
    local original_NetworkAdapterId = c_optical_module.NetworkAdapterId
    local original_PortID = c_optical_module.PortID
    local original_ncsi_schedulers = c_optical_module.ncsi_schedulers
    local original_ncsi_config_obj = c_optical_module.ncsi_config_obj
    local original_get_properties_res = c_optical_module.get_properties_res
    local original_package_id = c_optical_module.package_id
    local original_t_prop_without_bma = c_optical_module.t_prop_without_bma
    local original_is_prop_from_bma = c_optical_module.is_prop_from_bma
    local log_calls = {}
    local mock_scheduler = {}
    
    log.notice = function(self, fmt, ...) 
        table.insert(log_calls, {type='notice', fmt=fmt, args={...}}) 
    end
    log.error = function(self, fmt, ...) 
        table.insert(log_calls, {type='error', fmt=fmt, args={...}}) 
    end
    
    c_optical_module.NetworkAdapterId = "TestAdapter"
    c_optical_module.PortID = 1
    c_optical_module.ncsi_schedulers = {}
    c_optical_module.get_properties_res = {}
    c_optical_module.package_id = 1
    c_optical_module.t_prop_without_bma = {}
    c_optical_module.is_prop_from_bma = function(self, key) return false end
    c_optical_module.ncsi_config_obj = { 
        OpticalStaticInfo1 = function(self, params) return mock_scheduler end 
    }
    c_optical_module.connect_signal = function(self, signal, callback) 
        if signal == mock_scheduler.on_data_change then
            mock_scheduler.data_cb = callback
        elseif signal == mock_scheduler.on_error then
            mock_scheduler.error_cb = callback
        end
    end
    
    mock_scheduler.on_data_change = {}
    mock_scheduler.on_error = {}
    mock_scheduler.start = function() end
    
    c_optical_module:update_optical_module_static_info_by_ncsi(1)
    
    -- 测试启动日志
    lu.assertEquals(log_calls[1].fmt, 
        '%s optical_module_%s update optical module static info by ncsi start')
    
    -- 测试数据变化
    local test_data = {Manufacturer = "TestVendor", PartNumber = "PN12345"}
    mock_scheduler.data_cb(test_data)
    lu.assertTrue(c_optical_module.get_properties_res.StaticInfoFromNcsi)
    
    -- 测试错误回调
    c_optical_module.get_properties_res.StaticInfoFromNcsi = true
    mock_scheduler.error_cb()
    lu.assertFalse(c_optical_module.get_properties_res.StaticInfoFromNcsi)
    
    log.notice = original_notice
    log.error = original_error
    c_optical_module.NetworkAdapterId = original_NetworkAdapterId
    c_optical_module.PortID = original_PortID
    c_optical_module.ncsi_schedulers = original_ncsi_schedulers
    c_optical_module.ncsi_config_obj = original_ncsi_config_obj
    c_optical_module.get_properties_res = original_get_properties_res
    c_optical_module.package_id = original_package_id
    c_optical_module.t_prop_without_bma = original_t_prop_without_bma
    c_optical_module.is_prop_from_bma = original_is_prop_from_bma
end

-- 测试 update_optical_connector_type_by_ncsi 函数
function TEST_optical_module:test_update_optical_connector_type_by_ncsi()
    local log = require('mc.logging')
    local original_notice = log.notice
    local original_error = log.error
    local original_NetworkAdapterId = c_optical_module.NetworkAdapterId
    local original_PortID = c_optical_module.PortID
    local original_ncsi_schedulers = c_optical_module.ncsi_schedulers
    local original_ncsi_config_obj = c_optical_module.ncsi_config_obj
    local original_get_properties_res = c_optical_module.get_properties_res
    local original_package_id = c_optical_module.package_id
    local original_connect_signal = c_optical_module.connect_signal
    local log_calls = {}
    local mock_scheduler = {}
    
    log.notice = function(self, fmt, ...) 
        table.insert(log_calls, {type='notice', fmt=fmt, args={...}}) 
    end
    log.error = function(self, fmt, ...) 
        table.insert(log_calls, {type='error', fmt=fmt, args={...}}) 
    end
    
    c_optical_module.NetworkAdapterId = "TestAdapter"
    c_optical_module.PortID = 1
    c_optical_module.ncsi_schedulers = {}
    c_optical_module.get_properties_res = {}
    c_optical_module.package_id = 1
    c_optical_module.ncsi_config_obj = { 
        OpticalConnectorType1 = function(self, params) return mock_scheduler end 
    }
    c_optical_module.connect_signal = function(self, signal, callback) 
        if signal == mock_scheduler.on_data_change then
            mock_scheduler.data_cb = callback
        elseif signal == mock_scheduler.on_error then
            mock_scheduler.error_cb = callback
        end
    end
    
    mock_scheduler.on_data_change = {}
    mock_scheduler.on_error = {}
    mock_scheduler.start = function() end
    
    c_optical_module:update_optical_connector_type_by_ncsi(1)
    
    -- 测试启动日志
    lu.assertEquals(log_calls[1].fmt, 
        '%s optical_module_%s update optical connector type by ncsi start')
    
    -- 测试数据变化
    mock_scheduler.data_cb("LC")
    lu.assertTrue(c_optical_module.get_properties_res.ConnectorTypeFromNcsi)
    lu.assertEquals(#log_calls, 2)
    lu.assertEquals(log_calls[2].fmt, 
        '%s optical_module_%s update connector type to %s by ncsi')
    
    -- 测试错误回调
    c_optical_module.get_properties_res.ConnectorTypeFromNcsi = true
    mock_scheduler.error_cb()
    lu.assertFalse(c_optical_module.get_properties_res.ConnectorTypeFromNcsi)
    
    log.notice = original_notice
    log.error = original_error
    c_optical_module.NetworkAdapterId = original_NetworkAdapterId
    c_optical_module.PortID = original_PortID
    c_optical_module.ncsi_schedulers = original_ncsi_schedulers
    c_optical_module.ncsi_config_obj = original_ncsi_config_obj
    c_optical_module.get_properties_res = original_get_properties_res
    c_optical_module.package_id = original_package_id
    c_optical_module.connect_signal = original_connect_signal
end

-- 测试 update_optical_power_info_by_ncsi 函数
function TEST_optical_module:test_update_optical_power_info_by_ncsi()
    local log = require('mc.logging')
    local original_debug = log.debug
    local original_error = log.error
    local original_notice = log.notice
    local original_NetworkAdapterId = c_optical_module.NetworkAdapterId
    local original_PortID = c_optical_module.PortID
    local original_ncsi_schedulers = c_optical_module.ncsi_schedulers
    local original_ncsi_config_obj = c_optical_module.ncsi_config_obj
    local original_get_properties_res = c_optical_module.get_properties_res
    local original_package_id = c_optical_module.package_id
    local log_calls = {}
    local mock_scheduler = {}
    
    log.debug = function(self, fmt, ...) 
        table.insert(log_calls, {type='debug', fmt=fmt, args={...}}) 
    end
    log.error = function(self, fmt, ...) 
        table.insert(log_calls, {type='error', fmt=fmt, args={...}}) 
    end
    log.notice = function(self, fmt, ...) 
        table.insert(log_calls, {type='notice', fmt=fmt, args={...}}) 
    end
    
    c_optical_module.NetworkAdapterId = "TestAdapter"
    c_optical_module.PortID = 1
    c_optical_module.ncsi_schedulers = {}
    c_optical_module.get_properties_res = {}
    c_optical_module.package_id = 1
    c_optical_module.t_prop_without_bma = {}
    c_optical_module.is_prop_from_bma = function(self, key) return false end
    c_optical_module.ncsi_config_obj = { 
        OpticalPowerInfo1 = function(self, params) return mock_scheduler end 
    }
    c_optical_module.connect_signal = function(self, signal, callback) 
        if signal == mock_scheduler.on_data_change then
            mock_scheduler.data_cb = callback
        elseif signal == mock_scheduler.on_error then
            mock_scheduler.error_cb = callback
        end
    end
    
    mock_scheduler.on_data_change = {}
    mock_scheduler.on_error = {}
    mock_scheduler.start = function() end
    
    c_optical_module:update_optical_power_info_by_ncsi(1)
    
    -- 测试启动日志
    lu.assertEquals(log_calls[1].fmt, 
        '%s optical_module_%s update optical power info by ncsi start')
    
    -- 测试数据变化
    local test_data = {PowerClass = "Class1", MaxPower = 1.5}
    mock_scheduler.data_cb(test_data)
    lu.assertTrue(c_optical_module.get_properties_res.PowerInfoFromNcsi)
    
    -- 测试错误回调
    c_optical_module.get_properties_res.PowerInfoFromNcsi = true
    mock_scheduler.error_cb()
    lu.assertFalse(c_optical_module.get_properties_res.PowerInfoFromNcsi)
    
    log.debug = original_debug
    log.error = original_error
    log.notice = original_notice
    c_optical_module.NetworkAdapterId = original_NetworkAdapterId
    c_optical_module.PortID = original_PortID
    c_optical_module.ncsi_schedulers = original_ncsi_schedulers
    c_optical_module.ncsi_config_obj = original_ncsi_config_obj
    c_optical_module.get_properties_res = original_get_properties_res
    c_optical_module.package_id = original_package_id
    c_optical_module.t_prop_without_bma = original_t_prop_without_bma
    c_optical_module.is_prop_from_bma = original_is_prop_from_bma
end

-- 测试 update_optical_module_state_by_ncsi 函数
function TEST_optical_module:test_update_optical_module_state_by_ncsi()
    local log = require('mc.logging')
    local original_debug = log.debug
    local original_error = log.error
    local original_notice = log.notice
    local original_NetworkAdapterId = c_optical_module.NetworkAdapterId
    local original_PortID = c_optical_module.PortID
    local original_ncsi_schedulers = c_optical_module.ncsi_schedulers
    local original_ncsi_config_obj = c_optical_module.ncsi_config_obj
    local original_get_properties_res = c_optical_module.get_properties_res
    local original_package_id = c_optical_module.package_id
    local log_calls = {}
    local mock_scheduler = {}
    
    log.debug = function(self, fmt, ...) 
        table.insert(log_calls, {type='debug', fmt=fmt, args={...}}) 
    end
    log.error = function(self, fmt, ...) 
        table.insert(log_calls, {type='error', fmt=fmt, args={...}}) 
    end
    log.notice = function(self, fmt, ...) 
        table.insert(log_calls, {type='notice', fmt=fmt, args={...}}) 
    end
    
    c_optical_module.NetworkAdapterId = "TestAdapter"
    c_optical_module.PortID = 1
    c_optical_module.ncsi_schedulers = {}
    c_optical_module.get_properties_res = {}
    c_optical_module.package_id = 1
    c_optical_module.ncsi_config_obj = { 
        OpticalModuleState1 = function(self, params) return mock_scheduler end 
    }
    c_optical_module.connect_signal = function(self, signal, callback) 
        if signal == mock_scheduler.on_data_change then
            mock_scheduler.data_cb = callback
        elseif signal == mock_scheduler.on_error then
            mock_scheduler.error_cb = callback
        end
    end
    
    mock_scheduler.on_data_change = {}
    mock_scheduler.on_error = {}
    mock_scheduler.start = function() end
    
    c_optical_module:update_optical_module_state_by_ncsi(1)
    
    -- 测试启动日志
    lu.assertEquals(log_calls[1].fmt, 
        '%s optical_module_%s update optical module state by ncsi start')
    
    -- 测试数据变化
    mock_scheduler.data_cb("Enabled")
    lu.assertEquals(#log_calls, 2)
    lu.assertEquals(log_calls[2].fmt, 
        '%s optical_module_%s update module state to %s by ncsi')
    
    -- 测试错误回调
    c_optical_module.get_properties_res.ModuleStateFromNcsi = true
    mock_scheduler.error_cb()
    lu.assertFalse(c_optical_module.get_properties_res.ModuleStateFromNcsi)
    
    log.debug = original_debug
    log.error = original_error
    log.notice = original_notice
    c_optical_module.NetworkAdapterId = original_NetworkAdapterId
    c_optical_module.PortID = original_PortID
    c_optical_module.ncsi_schedulers = original_ncsi_schedulers
    c_optical_module.ncsi_config_obj = original_ncsi_config_obj
    c_optical_module.get_properties_res = original_get_properties_res
    c_optical_module.package_id = original_package_id
end

-- 为所有剩余的测试用例添加connect_signal mock的通用函数
local function add_connect_signal_mock(original_connect_signal, mock_scheduler)
    return function(self, signal, callback) 
        if signal == mock_scheduler.on_data_change then
            mock_scheduler.data_cb = callback
        elseif signal == mock_scheduler.on_error then
            mock_scheduler.error_cb = callback
        end
    end
end

return TEST_optical_module